#! /usr/local/bin/python
#-*- coding: utf-8 -*-

"""Représente une partie graphiquement.

Gestion de la découverte récursive des cases,
des évènements, etc.
"""

"""
Minesweeper 3K. Original implementation of the classic game of mines
for Python 3.
Copyright (C) 2010  Cedric Bonhomme

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Minesweeper 3K  Copyright (C) 2010  Cedric Bonhomme
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
"""

__author__ = "Jerome Hussenet, Cedric Bonhomme"
__date__ = "$Date: 2010/02/27 $"
__copyright__ = "Copyright (c) 2010 Jerome Hussenet, Copyright (c) 2010 Cedric Bonhomme"
__license__ = "GPL 3"

from tkinter import *
import time

import style
import roman

class grille_jeux(object):
    """Classe Grille_jeux

    Représente une partie graphiquement, découverte des cases.
    Gère les évènements.
    """
    def __init__(self, fen, canvas, grille, styl):
        """Intialise les données membre.

        Crée également la partie graphique et les événements.
        """
        self.newStyle = styl
        self.larg = self.newStyle.largCanevas
        self.text = self.newStyle.textStyle
        self.fen = fen
        self.perdu = False
        self.canvas = canvas
        self.canvas.configure(cursor = self.newStyle.curseur)
        self.grille = grille
        self.gauchepress = False
        self.droitpress = False
        self.dc = False
        self.nbcasecouverte = self.grille.hauteur * self.grille.largeur
        self.nb_drapeau = 0
        self.ac = 0
        self.al = 0

        ldec=[]
        for i in range(grille.hauteur):
            cdec=[]
            for j in range(grille.largeur):
                cdec.append(0)
            ldec.append(cdec)
        larg=self.larg
        self.grille_etat=ldec

        for i in range(grille.hauteur):
            for j in range(grille.largeur):
                self.canvas.create_image(larg*j, larg*i, image = self.newStyle.cache, anchor = NW)

        self.canvas.bind("<ButtonRelease-1>", self.release_gauche)
        self.canvas.bind("<ButtonRelease-3>", self.release_droit)
        self.canvas.bind("<ButtonPress-1>", self.press_gauche)
        self.canvas.bind("<ButtonPress-3>", self.press_droit)
        self.canvas.bind("<B1-Motion>", self.mvt_gauche)

    def changerStyle(self, styl):
        """Change les images images du canvas et le style des textes.
        """
        self.canvas.configure(cursor = self.newStyle.curseur)
        self.larg = self.newStyle.largCanevas
        self.text = self.newStyle.textStyle

        if self.newStyle.leStyle == "romain": # si style romain, on converti en chiffres romains
            self.fen.score.configure(text=roman.toRoman(int(self.fen.temps)) , **self.newStyle.textStyle)
            self.fen.dra.configure(text=roman.toRoman(self.grille.nbmines - self.nb_drapeau) , **self.newStyle.textStyle)
        else:
            self.fen.score.configure(text=str((int(self.fen.temps))) , **self.newStyle.textStyle)
            self.fen.dra.configure(text=str(self.grille.nbmines - self.nb_drapeau) , **self.newStyle.textStyle)

        if self.fen.fini == True:
            if self.perdu:
                self.fen.smiley.configure(image = self.newStyle.perdu)
            else:
                self.fen.smiley.configure(image = self.newStyle.gagne)
        elif self.fen.fini == False:
            self.fen.smiley.configure(image = self.newStyle.cool)

        self.redessiner()

    def charger(self, le):
        """Charge une partie sauvegardée.

        Initialise la grille d'état de la partie
        à partir de la liste le de la partie sauvegardée.
        """
        for i in range(self.grille.hauteur):
            s = ""
            for j in range(self.grille.largeur):
                etat = le[i][j]
                s = s + str(etat)
                self.grille_etat[i][j] = etat
                if etat == 2:
                    self.nb_drapeau = self.nb_drapeau + 1
            print(s)
        print(_("Chargement effectue"))
        self.redessiner()

    def redessiner(self):
        """Redessine graphiquement une partie.

        Fonction appelée lors du chargement d'une ancienne partie
        ou après un changement de style du jeu.
        """
        self.nbcasecouverte = self.grille.hauteur * self.grille.largeur
        for i in range(self.grille.hauteur):
            for j in range(self.grille.largeur):
                etat = self.grille_etat[i][j]
                if etat == 0:
                    self.canvas.create_image(self.larg*j, self.larg*i, image = self.newStyle.cache, anchor = NW)
                elif etat == 1:
                    self.nbcasecouverte = self.nbcasecouverte - 1
                    if self.grille.c[i][j] == 'm':
                        self.canvas.create_image(self.larg*j, self.larg*i, image = self.newStyle.mine, anchor = NW)
                    else:
                        nb = self.grille.getNbMinesVois(i,j)  #on recupere le nb de mines dans le voisinage
                        if nb > 0:    #si il y a au moins une mine, on affiche le nombres dans la case
                            self.canvas.create_image(self.larg*j, self.larg*i, image = self.newStyle.chiffre[nb], anchor = NW)
                        else:   #sinon, on decouvre toutes les cases voisines
                            self.canvas.create_image(self.larg*j, self.larg*i, image = self.newStyle.chiffre[0], anchor = NW)
                elif etat == 2:
                    if self.grille.c[i][j] != 'm' and self.perdu:
                        self.canvas.create_image(self.larg*j, self.larg*i, image = self.newStyle.croix, anchor = NW)
                    else:
                        self.canvas.create_image(self.larg*j, self.larg*i, image = self.newStyle.drapeau, anchor = NW)

    def mvt_gauche(self, event):
        if 0 <= event.x <= self.larg * self.grille.largeur \
                and 0 <= event.y <= self.larg * self.grille.hauteur:
            c = event.x/self.larg
            l = event.y/self.larg
            if not self.dc:
                if self.grille_etat[self.al][self.ac] == 0:
                    self.canvas.create_image(self.larg*self.ac, self.larg*self.al, image = self.newStyle.cache, anchor = NW)
                if not self.droitpress:
                    try:
                        if self.grille_etat[l][c] == 0:
                            self.canvas.create_image(self.larg*c, self.larg*l, image = self.newStyle.chiffre[0], anchor = NW)
                        self.ac=c
                        self.al=l
                    except:
                          pass
            else:
                self.masquer_voisins(self.al, self.ac)
                self.afficher_voisins(l, c)
                self.ac = c
                self.al = l

    def afficher_voisins(self, l, c):
        """Affiche les voisins de (l, c)
        """
        v = self.grille.getVoisinage(l, c)
        for i in v:
            if self.grille_etat[i[0]][i[1]] == 0:
                self.canvas.create_image(self.larg*i[1], self.larg*i[0], image = self.newStyle.chiffre[0], anchor = NW)

    def masquer_voisins(self, l, c):
        """Masque les voisins de (l, c)
        """
        v = self.grille.getVoisinage(l,c)
        for i in v:
            if self.grille_etat[i[0]][i[1]] == 0:
                self.canvas.create_image(self.larg*i[1], self.larg*i[0], image = self.newStyle.cache, anchor = NW)

    def press_gauche(self, event):
        """Clic droit, découvre une case.
        """
        #print "gauche appuye"
        self.gauchepress = True
        c = int(event.x/self.larg)
        l = int(event.y/self.larg)
        if 0 <= event.x <= self.larg * self.grille.largeur \
                and 0 <= event.y <= self.larg * self.grille.hauteur:
            if self.grille_etat[l][c] == 0:
                self.fen.smiley.configure(image = self.newStyle.peur)
        if self.droitpress == True:
            self.dc = True
            #print "dc"

            self.afficher_voisins(l,c)

    def press_droit(self, event):
        """Clic droit
        """
        #print "droit appuye"
        self.droitpress = True
        if 0 <= event.x <= self.larg * self.grille.largeur \
            and 0 <= event.y <= self.larg * self.grille.hauteur:
            if self.gauchepress == True:
                self.dc = True
                #print "dc"
                c = int(event.x/self.larg)
                l = int(event.y/self.larg)
                self.afficher_voisins(l,c)

    def drapeau(self, l, c):
        """Place un drapeau.
        """
        #print "d:"+str(l)+":"+str(c)+"->"+str(self.grille_etat[l][c])
        if self.grille_etat[l][c] == 0:
            if self.nb_drapeau < self.grille.nbmines:
                self.grille_etat[l][c] = 2
                self.nb_drapeau = self.nb_drapeau + 1
                self.canvas.create_image(self.larg*c, self.larg*l, image = self.newStyle.drapeau, anchor = NW)
                if self.nb_drapeau == self.nbcasecouverte and self.nb_drapeau == self.grille.nbmines:
                    self.terminer(False)
        elif self.grille_etat[l][c] == 2:
            self.grille_etat[l][c] = 0
            self.nb_drapeau = self.nb_drapeau - 1
            self.canvas.create_image(self.larg*c, self.larg*l, image = self.newStyle.cache, anchor = NW)

        if self.newStyle.leStyle == "romain": # si style romain, on converti en chiffres romains
            self.fen.dra.configure(text=roman.toRoman(self.grille.nbmines - self.nb_drapeau))
        else:
            self.fen.dra.configure(text=str(self.grille.nbmines - self.nb_drapeau) , **self.newStyle.textStyle)

    def inutile(self, event):
        """Permet de <<désactiver>> les binds.
        """
        pass

    def terminer(self, perdu):
        """Fin de partie (gagnée ou perdue).

        Désactive les binds.
        """
        #print "fin"
        self.canvas.bind("<ButtonRelease-1>", self.inutile)
        self.canvas.bind("<ButtonRelease-3>", self.inutile)
        self.canvas.bind("<ButtonPress-1>", self.inutile)
        self.canvas.bind("<ButtonPress-3>", self.inutile)
        self.canvas.bind("<B1-Motion>", self.inutile)
        self.perdu = perdu
        self.decouvrirMine()
        self.fen.terminer(perdu)

    def decouvrirMine(self):
        """Decouvre les mines à la fin du jeu.

        Si des indicateurs on été placés au mauvais endroit, l'image est remplacée.
        """
        for i in range(self.grille.hauteur):
            for j in range(self.grille.largeur):
                etat = self.grille_etat[i][j]
                mine = self.grille.c[i][j]
                if etat == 2 and mine != "m":
                    self.canvas.create_image(self.larg*j, self.larg*i, image = self.newStyle.croix, anchor = NW)
                if etat == 0 and mine == "m":
                    self.canvas.create_image(self.larg*j, self.larg*i, image = self.newStyle.mine, anchor = NW)
                    self.grille_etat[i][j] = 1

    def decouvrir(self, l, c):
        """Découverte récursive des mines.
        """
        if self.grille_etat[l][c] == 0:   #si la case est cache
            self.grille_etat[l][c] = 1    #on decouvre la case
            self.nbcasecouverte = self.nbcasecouverte - 1
            #print "decouvert:" + str(l) + "," + str(c)
            #print "reste: " + str(self.nbcasecouverte)
            #print "drapeau: " + str(self.nb_drapeau)
            #print "mine: " + str(self.grille.nbmines)
            if self.nb_drapeau==self.nbcasecouverte and self.nb_drapeau==self.grille.nbmines:
                self.terminer(False)
            if self.grille.c[l][c] == 'm':    #si cette case est une mine
                self.canvas.create_image(self.larg*c, self.larg*l, image = self.newStyle.mine, anchor = NW)
                self.terminer(True)
            else:
                nb = self.grille.getNbMinesVois(l,c)  #on recupere le nb de mines dans le voisinage
                if nb > 0:    #si il y a au moins une mine, on affiche le nombres dans la case
                    self.canvas.create_image(self.larg*c, self.larg*l, image = self.newStyle.chiffre[nb], anchor = NW)
                else:   #sinon, on decouvre toutes les cases voisines
                    self.canvas.create_image(self.larg*c, self.larg*l, image = self.newStyle.chiffre[0], anchor = NW)
                    v = self.grille.getVoisinage(l, c)
                    for i in v:
                        self.decouvrir(i[0], i[1])
            #print self.nbcasecouverte

    def decouvrir_rapide(self, l, c):
        """Découverte rapide.

        Appelée lors du clic droit-gauche.
        """
        if 0 <= c <= self.grille.largeur \
                and 0 <= l <= self.grille.hauteur:
            if self.grille_etat[l][c] == 1:
                nb_drap = 0
                nb_mines = self.grille.getNbMinesVois(l,c)
                v = self.grille.getVoisinage(l, c)
                for i in v:
                    if (self.grille_etat[i[0]][i[1]] == 2):
                        nb_drap = nb_drap + 1
                if nb_drap == nb_mines:
                    for i in v:
                        self.decouvrir(i[0], i[1])
            self.masquer_voisins(l, c)

    def release_gauche(self, event):
        """Relâchement du bouton droit.
        """
        self.fen.smiley.configure(image = self.newStyle.cool)
        self.gauchepress = False
        if 0 <= event.x <= self.larg * self.grille.largeur \
                and 0 <= event.y <= self.larg * self.grille.hauteur:
            c = int(event.x / self.larg)
            l = int(event.y / self.larg)
            if not self.dc: #si l'action n'est pas dans un double clique
                self.decouvrir(l,c) #on decouvre la case cliquee
            else:
                self.decouvrir_rapide(l, c)
                if self.droitpress == False:
                    self.dc=False
        else:
            self.redessiner()

    def release_droit(self, event):
        """Relâchement du bouton droit.
        """
        self.droitpress = False
        if 0 <= event.x <= self.larg * self.grille.largeur \
                and 0 <= event.y <= self.larg * self.grille.hauteur:
            c = int(event.x / self.larg)
            l = int(event.y / self.larg)
            if not self.dc:
                self.drapeau(l,c)
            else:
                self.decouvrir_rapide(l, c)
                if self.gauchepress == False:
                    self.dc = False
        self.dc = False
        self.redessiner()